/*
 * @Author: zhangshu
 * @email: shiliang.zhang@tuya.com
 * @LastEditors: Please set LastEditors
 * @file name: app_dev_register.c
 * @Description: 
 * @Copyright: HANGZHOU TUYA INFORMATION TECHNOLOGY CO.,LTD
 * @Company: http://www.tuya.com
 * @Date: 2022-02-08
 * @LastEditTime: 2022-02-08
 */
#include "app_dev_register.h"
#include "tal_network_mgr.h"
#include "tal_reporting.h"
#include "tkl_endpoint_register.h"

#ifndef GET_ARRAY_LEN
#define GET_ARRAY_LEN(x)    (SIZEOF(x) / SIZEOF(x[0]))
#endif

/*****************************************************Server attribute list********************************************************************/
//power attribute list
#define POWER_ATTR_LIST \
    { 0x0000, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_SINGLETON), 0, (UINT8_T*)0x0000UL }, /* 10 / Power Configuration / mains voltage*/\
    { 0x0020, ATTR_INT8U_ATTRIBUTE_TYPE, 1, (ATTR_MASK_SINGLETON), 0, (UINT8_T*)0x00UL  }, /* 11 / Power Configuration / battery voltage*/\
    { 0x0021, ATTR_INT8U_ATTRIBUTE_TYPE, 1, (ATTR_MASK_SINGLETON), 0, (UINT8_T*)0xC8 } , /* 12 / Power Configuration / battery percentage remaining*/\
    { 0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_SINGLETON), 0, (UINT8_T*)0x0001  }, /* 13 / Power Configuration / cluster revision*/\

//ias zone attribute list
#define IAS_ZONE_SERVER_ATTR_LIST \
    { 0x0000, ATTR_ENUM8_ATTRIBUTE_TYPE, 1, (ATTR_MASK_TOKEN_FAST), 0, { (UINT8_T*)0x00 } }, /* 21 / IAS Zone / zone state*/\
    { 0x0001, ATTR_ENUM16_ATTRIBUTE_TYPE, 2, (ATTR_MASK_TOKEN_FAST), 0, { (UINT8_T*)0x000d } }, /* 22 / IAS Zone / zone type*/\
    { 0x0002, ATTR_BITMAP16_ATTRIBUTE_TYPE, 2, (ATTR_MASK_READABLE), 0, { (UINT8_T*)0x0000 } }, /* 23 / IAS Zone / zone status*/\
    { 0x0010, ATTR_IEEE_ADDRESS_ATTRIBUTE_TYPE, 8, (ATTR_MASK_TOKEN_FAST|ATTR_MASK_WRITABLE), 0, { NULL } }, /* 24 / IAS Zone / IAS CIE address*/\
    { 0x0011, ATTR_INT8U_ATTRIBUTE_TYPE, 1, (ATTR_MASK_TOKEN_FAST), 0, { (UINT8_T*)0xff } }, /* 25 / IAS Zone / Zone ID*/\
    { 0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_READABLE), 0, { (UINT8_T*)0x0001 } }, /* 26 / IAS Zone / cluster revision*/

// power attribute
CONST TAL_ATTR_T power_attr_list[] = {
    POWER_ATTR_LIST
};

// ias zone attribute
CONST TAL_ATTR_T ias_zone_attr_list[] = {
    IAS_ZONE_SERVER_ATTR_LIST
};

/*****************************************************Client attribute list********************************************************************/
#define IDENTIFY_CLIENT_ATTR_LIST \
    { 0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_CLIENT), 0, { (UINT8_T*)0x0001 } }, /* 13 / Identify / cluster revision*/

#define  GROUP_CLIENT_ATTR_LIST   \
    { 0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_CLIENT), 0, (UINT8_T*)0x0001 },

#define  ON_OFF_CLIENT_ATTR_LIST   \
    { 0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_CLIENT), 0, (UINT8_T*)0x0001 },

#define  ZLL_CLIENT_ATTR_LIST   \
    { 0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_CLIENT), 0, (UINT8_T*)0x0001 },

#define SCENE_ATTR_LIST                                                                                                       \
    {0x0000, ATTR_INT8U_ATTRIBUTE_TYPE, 1, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x00},        /* 15 / Scenes / scene count*/   \
    {0x0001, ATTR_INT8U_ATTRIBUTE_TYPE, 1, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x00},    /* 16 / Scenes / current scene*/ \
    {0x0002, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x0000}, /* 16 / Scenes / current group*/ \
    {0x0003, ATTR_BOOLEAN_ATTRIBUTE_TYPE, 1, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x00},  /* 17 / Scenes / scene valid*/   \
    {0x0004, ATTR_BITMAP8_ATTRIBUTE_TYPE, 1, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x00},  /* 18 / Scenes / name support*/  \
    {0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x0002}, /* 19 / Scenes / cluster revision*/

#define GROUP_ATTR_LIST                                                                                                      \
    {0x0000, ATTR_BITMAP8_ATTRIBUTE_TYPE, 1, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x00},      /* 12 / Groups / name support*/ \
    {0xFFFD, ATTR_INT16U_ATTRIBUTE_TYPE, 2, (ATTR_MASK_READABLE), 0, (UINT8_T *)0x0002}, /* 13 / Groups / cluster revision*/

// identify client attribute
CONST TAL_ATTR_T identify_client_attr_list[] = {
    IDENTIFY_CLIENT_ATTR_LIST
};

// group client attribute
CONST TAL_ATTR_T group_client_attr_list[] = {
    GROUP_CLIENT_ATTR_LIST
};

// onoff client attribute
CONST TAL_ATTR_T onoff_client_attr_list[] = {
    ON_OFF_CLIENT_ATTR_LIST
};

// zll client attribute
CONST TAL_ATTR_T zll_client_attr_list[] = {
    ZLL_CLIENT_ATTR_LIST
};

const TAL_ATTR_T scene_attr_list[] = {
    SCENE_ATTR_LIST};

const TAL_ATTR_T group_attr_list[] = {
    GROUP_ATTR_LIST};

#define DEF_CLUSTER_SCENES_CLUSTER_ID(a) \
    {CLUSTER_SCENES_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a))},

#define DEF_CLUSTER_POWER_CLUSTER_ID(a) \
    { CLUSTER_POWER_CONFIG_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a)) },

#define DEF_CLUSTER_IDENTIFY_CLUSTER_ID(a) \
    { CLUSTER_IDENTIFY_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a)) },

#define DEF_CLUSTER_GROUPS_CLUSTER_ID(a) \
    { CLUSTER_GROUPS_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a)) },

#define DEF_CLUSTER_ON_OFF_CLUSTER_ID(a) \
    { CLUSTER_ON_OFF_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a)) },

#define DEF_CLUSTER_IAS_ZONE_CLUSTER_ID(a) \
    { CLUSTER_IAS_ZONE_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a)) },

#define DEF_CLUSTER_ZLL_COMMISSIONING_CLUSTER_ID(a) \
    { CLUSTER_ZLL_COMMISSIONING_CLUSTER_ID, (TAL_ATTR_T *)&((a)[0]), GET_ARRAY_LEN((a)) },


// server cluster list
CONST TAL_CLUSTER_T app_server_cluster_list[] = {
    DEF_CLUSTER_GROUPS_CLUSTER_ID(group_attr_list)
    DEF_CLUSTER_SCENES_CLUSTER_ID(scene_attr_list)
    DEF_CLUSTER_POWER_CLUSTER_ID(power_attr_list)
    DEF_CLUSTER_IAS_ZONE_CLUSTER_ID(ias_zone_attr_list)
};

// client cluster list
CONST TAL_CLUSTER_T app_client_cluster_list[] = {
    DEF_CLUSTER_IDENTIFY_CLUSTER_ID(identify_client_attr_list)
    DEF_CLUSTER_GROUPS_CLUSTER_ID(group_client_attr_list)
    DEF_CLUSTER_ON_OFF_CLUSTER_ID(onoff_client_attr_list)
    DEF_CLUSTER_ZLL_COMMISSIONING_CLUSTER_ID(zll_client_attr_list)
};

#define SERVER_CLUSTER_NUM GET_ARRAY_LEN(app_server_cluster_list)
#define CLIENT_CLUSTER_NUM GET_ARRAY_LEN(app_client_cluster_list)

// zigbee 3.0 report attribute through report table
#define ZG_REPORTING_CONFIG \
        { TAL_REPORT_DIRECTION_REPORTED, 0x01, CLUSTER_POWER_CONFIG_CLUSTER_ID, 0x0020, ZG_CLUSTER_MASK_SERVER, 0x0000, 65535, 14400, 0 },\
        { TAL_REPORT_DIRECTION_REPORTED, 0x01, CLUSTER_POWER_CONFIG_CLUSTER_ID, 0x0021, ZG_CLUSTER_MASK_SERVER, 0x0000, 65535, 14400, 0 }

TAL_REPORT_TABLE_T g_report_config[] = {
        ZG_REPORTING_CONFIG
};

//endpoint descriptor
TAL_ENDPOINT_T dev_endpoint_desc[] = {
    {1, ZHA_PROFILE_ID, ZG_DEVICE_ID_IAS_ZONE, SERVER_CLUSTER_NUM, (TAL_CLUSTER_T *)&app_server_cluster_list[0], CLIENT_CLUSTER_NUM, (TAL_CLUSTER_T *)&app_client_cluster_list[0]},
};


/**
 * @brief check if the cluster already in registertion list
 * NOTE: only for server clusters attributes
 *
 * @param[in] cluster_id: cluster id
 * @return TRUE if the cluster exists in registertion list or FALSE
 */
BOOL_T is_server_cluster_valid(UINT16_T cluster_id)
{
    for (UINT8_T i = 0; i < SERVER_CLUSTER_NUM; i++) {
        if (app_server_cluster_list[i].cluster_id == cluster_id) {
            return TRUE;
        }
    }
    return FALSE;
}

/**
 * @brief check if the attribute  of cluster already in registertion list
 * NOTE: only for server clusters attributes
 *
 * @param[in] cluster_id: cluster id
 * @param[in] attribute_id: attribute id
 * @return TRUE when in registertion list else FALSE
 */
BOOL_T is_server_attribute_valid(UINT16_T cluster_id, UINT16_T attribute_id)
{
    for (UINT8_T i = 0; i < SERVER_CLUSTER_NUM; i++) {
        if (app_server_cluster_list[i].cluster_id == cluster_id) {
            for (UINT8_T j = 0; j < app_server_cluster_list[i].attr_sums; j++) {
                if (app_server_cluster_list[i].attr_list[j].attr_id == attribute_id) {
                    return TRUE;
                }
                
            }
        }
    }
    return FALSE;
}

/**
 * @brief register router or sleep device
 * @return none
 */
STATIC VOID_T app_sleep_device_node_init(VOID_T)
{
    /*TAL_ZG_NODE_CFG_T node_config = {
        .node_type = ZG_ROUTER,//zigbee type, router, end device or sleep end device
        .tx_power = 10,//set tx power
        .scan_interval = 0,//beacon scan interval
        .scan_duration = ZG_SCAN_DURATION_3,//beacon scan interval 153.6 ms
    };*/
            // sleep end device node init
     TAL_ZG_NODE_CFG_T node_config = {
         .node_type = ZG_SLEEPY_END_DEVICE,
         .tx_power = 10,
         .scan_interval = 100,
         .scan_duration = ZG_SCAN_DURATION_3,
         .config.sleep_ed_cfg.poll_config.forever_flag = 0,
         .config.sleep_ed_cfg.poll_config.fast_swicth_parent = 0,
         .config.sleep_ed_cfg.poll_config.interval_ms = 250,
         .config.sleep_ed_cfg.poll_config.max_failed_times = 10,
         .config.sleep_ed_cfg.poll_config.duration_after_data_ms = 1000,
         .config.sleep_ed_cfg.poll_config.duration_after_join_ms = 60000,
         .config.sleep_ed_cfg.poll_config.duration_after_rejoin_ms = 15000,
         .config.sleep_ed_cfg.rejoin_config.power_on_active = 1,
         .config.sleep_ed_cfg.rejoin_config.send_data_active = 1,
         .config.sleep_ed_cfg.rejoin_config.attempts = 3,
         .config.sleep_ed_cfg.rejoin_config.interval = 3000,
     };
    //config zigbee node
    tal_zg_node_config(&node_config);
}

/**
 * @brief config join strategy
 * @return none
 */
STATIC VOID_T dev_joined_config(VOID_T)
{
    TAL_ZG_JOIN_CFG_T join_config = {
        .auto_join_power_on_flag = FALSE,//defalut power on start join or not
        .auto_join_remote_leave_flag = TRUE,//default start join or not when receivew remote leave request
        .join_timeout = 180*1000,//join timeout times
    };
    //config join prameter
    tal_zg_join_config(&join_config);
}

/**
 * @brief register zigbee parameter
 * @return none
 */
VOID_T dev_zigbee_init(VOID_T)
{
    //register zigbee endpoint
    tal_zg_endpoint_register(dev_endpoint_desc, GET_ARRAY_LEN(dev_endpoint_desc));

    //zigbee node configuration
    app_sleep_device_node_init();

    //zigbee joining network configuration
    dev_joined_config();

    //tal_zg_reporting_init(g_report_config, GET_ARRAY_LEN(g_report_config));


}

